﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Sustainalytics.DynamicsCRMGateway.Entities;
using Account = Sustainalytics.DynamicsCRMGateway.Entities.Account;
using AccountFeatureEnum = Sustainalytics.Auth.Claims.AccountFeature;
using ProductUniverse = Sustainalytics.DynamicsCRMGateway.Entities.ProductUniverse;
using Sustainalytics.Entities.ESGRatings;
using Sustainalytics.DynamicsCRMGateway;
using System.Linq.Expressions;
using Sustainalytics.DataLayer.Shared;
using System.Threading;


namespace Sustainalytics.Universes.Synchronization
{
    class UniverseInfo : IUniverseInfo
    {
        public IEnumerable<Account> AccountSet
        {
            get;
            set;
        }

        public IEnumerable<AccountUniverse> AccountUniverseSet
        {
            get;
            set;
        }
        public IEnumerable<CompaniesGroup> CompaniesGroupSet
        {
            get;
            set;
        }
        public IEnumerable<ProductUniverse> ProductUniverseSet
        {
            get;
            set;
        }

        public IEnumerable<UniverseFeatureProductUniverseBridge> UniverseFeatureProductUniverseBridgeSet
        {
            get;
            set;
        }

        public IEnumerable<UniverseFeature> UniverseFeatureSet
        {
            get;
            set;
        }
        public IEnumerable<CompaniesGroupConstituent> CompaniesGroupConstituentSet
        {
            get;
            set;
        }

        public IEnumerable<Company> CompanySet
        {
            get;
            set;
        }

        public IEnumerable<CompaniesGroupAccountUniverseBridge> CompaniesGroupAccountUniverseBridgeSet
        {
            get;
            set;
        }

        public ReferenceUniverse[] ReferenceUniverseSet
        {
            get;
            set;
        }

        private int _maxParalelism;
        private int _bulkSize;
        private string _crmConnString;
        private string _clientDwConnString;

        public UniverseInfo(int maxParalelism, int bulkSize, string crmConnString, string clientDwConnString)
        {
            _maxParalelism = maxParalelism;
            _bulkSize = bulkSize;
            _crmConnString = crmConnString;
            _clientDwConnString = clientDwConnString;
        }

        public void LoadData()
        {
            if (SynchronizationContext.Current == null)
                SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());

            var filters = new WhereClause<Account, object>[]
                {
                    new WhereClause<Account, object>(x => x.RelationshipType, WhereClauseOperator.Equal, (int?) AccountRelationshipType.Client),
                    new WhereClause<Account, object>(x => x.RelationshipType, WhereClauseOperator.Equal, (int?) AccountRelationshipType.Demo),
                    new WhereClause<Account, object>(x => x.RelationshipType, WhereClauseOperator.Equal, (int?) AccountRelationshipType.Prospect),
                };

            var t4 = (new Crm2MemoryDataMover<CompaniesGroupConstituent>(_maxParalelism, _crmConnString, _bulkSize * 5, new Expression<Func<CompaniesGroupConstituent, object>>[] { x => x.Id, x => x.Name, x => x.CompaniesGroupRef.Id, x => x.CompanyRef.Id }, null)).Run();
            t4.Wait();
            var t5 = (new Crm2MemoryDataMover<Company>(_maxParalelism, _crmConnString, _bulkSize * 5, new Expression<Func<Company, object>>[] { x => x.Id, x => x.CapitalIqId }, null)).Run();
            t5.Wait();
            var t1 = (new Crm2MemoryDataMover<Account>(_maxParalelism, _crmConnString, _bulkSize, new Expression<Func<Account, object>>[] { x => x.Id, x => x.Name, x => x.Status }, filters)).Run();
            t1.Wait();
            var t2 = (new Crm2MemoryDataMover<AccountUniverse>(_maxParalelism, _crmConnString, _bulkSize, new Expression<Func<AccountUniverse, object>>[] { x => x.AccountRef.Id, x => x.ProductUniverseRef.Id }, null)).Run();
            t2.Wait();
            var t3 = (new Crm2MemoryDataMover<CompaniesGroup>(_maxParalelism, _crmConnString, _bulkSize, new Expression<Func<CompaniesGroup, object>>[] { x => x.Id, x => x.Name, x => x.IsStandard }, null)).Run();
            t3.Wait();
            var t6 = (new Crm2MemoryDataMover<ProductUniverse>(_maxParalelism, _crmConnString, _bulkSize, new Expression<Func<ProductUniverse, object>>[] { x => x.Id, x => x.Name }, null)).Run();
            t6.Wait();
            var t7 = (new Crm2MemoryDataMover<UniverseFeatureProductUniverseBridge>(_maxParalelism, _crmConnString, _bulkSize, new Expression<Func<UniverseFeatureProductUniverseBridge, object>>[] { x => x.Id, x => x.ProductUniverseId, x => x.UniverseFeatureId }, null)).Run();
            t7.Wait();
            var t8 = (new Crm2MemoryDataMover<UniverseFeature>(_maxParalelism, _crmConnString, _bulkSize, new Expression<Func<UniverseFeature, object>>[] { x => x.Id, x => x.Name }, null)).Run();
            t8.Wait();

            var t9 = (new Crm2MemoryDataMover<CompaniesGroupAccountUniverseBridge>(_maxParalelism, _crmConnString, _bulkSize, new Expression<Func<CompaniesGroupAccountUniverseBridge, object>>[] { x => x.Id, x => x.AccountUniverseId, x => x.CompaniesGroupId }, null)).Run();
            var t10 = (new TaskFactory<ReferenceUniverse[]>()).StartNew(() => LoadReferenceUniverses(_clientDwConnString));


            Task.WaitAll(new Task[] {t9, t10 }, TimeSpan.FromMinutes(15));


            AccountSet = t1.Result.Where(x => x.Status == 0);
            AccountUniverseSet = t2.Result.Where(x => x.AccountRef != null && x.ProductUniverseRef != null);
            CompaniesGroupSet = t3.Result;
            ProductUniverseSet = t6.Result;
            UniverseFeatureProductUniverseBridgeSet = t7.Result;
            UniverseFeatureSet = t8.Result;
            CompaniesGroupConstituentSet = t4.Result.Where(x => x.CompaniesGroupRef != null && x.CompanyRef != null);
            CompanySet = t5.Result;
            CompaniesGroupAccountUniverseBridgeSet = t9.Result;
            ReferenceUniverseSet = t10.Result;
        }

        public void Clean()
        {
            AccountSet = null;
            AccountUniverseSet = null;
            CompaniesGroupSet = null;
            ProductUniverseSet = null;
            UniverseFeatureProductUniverseBridgeSet = null;
            UniverseFeatureSet = null;
            CompaniesGroupConstituentSet = null;
            CompanySet = null;
            CompaniesGroupAccountUniverseBridgeSet = null;
            ReferenceUniverseSet = null;
        }

        private ReferenceUniverse[] LoadReferenceUniverses(string clientDWConnectionString)
        {
            var referenceUniversesRepositoryCollection = new RepositoryCollection<ReferenceUniverse>(clientDWConnectionString);
            IEnumerable<ReferenceUniverse> referenceUniverses = referenceUniversesRepositoryCollection.ReadAll();
            return referenceUniverses.ToArray();
        }
    }
}
